#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

#include <sys/mman.h>
#include "headers/PanberryMain.h"
#include "headers/PanberryRotation.h"

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000)	/* GPIO controller */
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

int mem_fd;
void *gpio_map;

// I/O access
volatile unsigned *gpio;
#define GPIO_LEV *(gpio+13)

// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
#define GPIO_SET *(gpio+7)	// sets   bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10)	// clears bits which are 1 ignores bits which are 0

void setup_io();


/**
 * main
 * @param argv количество параметров командной строки (считая имя программы)
 * @param argv массив строк-параметров командной строки
 */
int main(int argc, char *argv[])
{
    int cmdFd;

    // Set up gpi pointer for direct register access
    setup_io();

    if ((cmdFd = open(CMD_FIFO, O_RDWR | O_NONBLOCK)) <= 0) {
	perror("open");
	return EXIT_FAILURE;
    }

	int *lastButton = NULL;
	
    while (1)
    {
        unsigned int value = GPIO_LEV;
        int pin21_value = ((value & (1 << 21)) != 0);
        int pin22_value = ((value & (1 << 22)) != 0);	//start
        int pin23_value = ((value & (1 << 23)) != 0);

        if (pin21_value == 1 && lastButton != &pin21_value) {
            char cmd[128];
            sprintf(cmd, "%d", ACTION_ROTATE_L);
            write(cmdFd, cmd, strlen(cmd));
            lastButton = &pin21_value;

        } else if (pin23_value == 1 && lastButton != &pin23_value) {
            char cmd[128];
            sprintf(cmd, "%d", ACTION_ROTATE_R);
            write(cmdFd, cmd, strlen(cmd));
            lastButton = &pin23_value;

        } else if (pin22_value == 1 && lastButton != &pin22_value) {
            char cmd[128];
            sprintf(cmd, "%d", ACTION_START);
            write(cmdFd, cmd, strlen(cmd));
            fprintf(stderr, "start\n");
            lastButton = &pin22_value;
        } else if (pin21_value == 0 && pin22_value == 0 && pin23_value == 0)
            lastButton = NULL;

        usleep(1000);
    }

	close(cmdFd);

    return EXIT_SUCCESS;
}



//
// Set up a memory regions to access GPIO
//
void setup_io()
{
    /* open /dev/mem */
    if ((mem_fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
	printf("can't open /dev/mem \n");
	exit(-1);
    }

    /* mmap GPIO */
    gpio_map = mmap(NULL,	//Any adddress in our space will do
		    BLOCK_SIZE,	//Map length
		    PROT_READ | PROT_WRITE,	// Enable reading & writting to mapped memory
		    MAP_SHARED,	//Shared with other processes
		    mem_fd,	//File to map
		    GPIO_BASE	//Offset to GPIO peripheral
	);

    close(mem_fd);		//No need to keep mem_fd open after mmap

    if (gpio_map == MAP_FAILED) {
        //printf("mmap error %c\n", (int) *gpio_map);	//errno also set!
        perror("mmap");
        exit(-1);
    }
    // Always use volatile pointer!
    gpio = (volatile unsigned *) gpio_map;
}				// setup_io
